import struct
from udp_handle import Udp_Multicast_Receiver
import threading
import queue
from config import config_singleton
import asyncio
from utils import Constants, MsgBean, sys_logger, NetMsgBean, FlowCode


class Parser:
    """根据udp接收的数据，进行解码"""

    def __init__(self, udp_recv: Udp_Multicast_Receiver, max_msgbean_size, drop_bytes):
        self._udp_recv = udp_recv
        self.break_parse = False
        self._queue = queue.Queue(maxsize=max_msgbean_size)
        self._frame_head_size = struct.calcsize("<BHIII")
        self._var_size = struct.calcsize("<Hf")
        self._drop_bytes_everytime = drop_bytes
        self.drop_counter = 0
        self.netmsg_cnt = 0
        self.busmsg_cnt = 0

    def stop(self):
        self._queue.put(None)
        self.break_parse = True

    def get_msgbean(self) -> MsgBean:
        return self._queue.get()
    
    def do_parse(self):

        parse_state = 0
        data = b''
        while not self.break_parse:
            temp = self._udp_recv.get_recv_data()
            if temp is not None:
                data = data + temp
            else:
                break
                # data = data.join(temp)  # 该方法效率更高
            while len(data) >= Constants.UDP_FRAME_HEAD_LEN:
                # if (len(data) < Constants.UDP_FRAME_HEAD_LEN):
                #     continue
                # 还未解析到帧头信息
                if parse_state == 0:
                    frame_head = struct.unpack("<BHIII", data[:self._frame_head_size])

                    while frame_head != Constants.UDP_FRAME_HEADER and len(data) > Constants.UDP_FRAME_HEAD_LEN:
                        # 固定丢弃2个byte
                        data = data[self._drop_bytes_everytime:]
                        self.drop_counter  = self.drop_counter + 2
                        frame_head = struct.unpack("<BHIII", data[:self._frame_head_size])

                    if frame_head == Constants.UDP_FRAME_HEADER:
                        parse_state = 1
                    else:
                        continue

                if parse_state == 1:
                    data_len = struct.unpack("<H", data[Constants.UDP_FRAME_HEAD_LEN - 2 : Constants.UDP_FRAME_HEAD_LEN])

                    # 数据长度不够，继续接收数据
                    if data_len[0] + Constants.UDP_FRAME_HEAD_LEN > len(data):
                        parse_state = 0
                        break

                    table_num = struct.unpack("<H", data[Constants.UDP_FRAME_HEAD_LEN : Constants.UDP_FRAME_HEAD_LEN + 2])
                    table_frame = data[Constants.UDP_FRAME_HEAD_LEN + 2: data_len[0] + Constants.UDP_FRAME_HEAD_LEN]

                    if table_num[0] != 1999:
                        if self.parse_msgbean(table_num=table_num[0], frame=table_frame):
                            self.busmsg_cnt = self.busmsg_cnt + 1
                    else:
                        if self.parse_netbean(table_num=table_num[0], frame=table_frame):
                            self.netmsg_cnt = self.netmsg_cnt + 1

                    data = data[data_len[0] + Constants.UDP_FRAME_HEAD_LEN:]
                    # 重新开始找帧头
                    parse_state = 0
        
        sys_logger.info(f"Parser stopped, total dropped bytes: {self.drop_counter}, net msg parse total:{self.netmsg_cnt}, bus msg parse total:{self.busmsg_cnt}.")



    def parse_msgbean(self, table_num, frame):

        msgbean = MsgBean()
        msgbean.table_num = table_num

        # 长度不是var_size的整数倍
        if len(frame) % self._var_size != 0:
            sys_logger.error(f"Frame length error or unrecognized frame: {frame.hex()}")
            return False

        iter_vars = struct.iter_unpack("<Hf", frame)

        try:
            for item in iter_vars:
                # item[0] 编号编号，从1开始，item[1]为变量的值, 解码后的数据按照1~N的顺序排列
                msgbean.vars.append(item[1])
                # msgbean.vars[item[0]] = item[1]
            # 以下方式可以提高一倍的速度
            # [msgbean.vars[item[0]] = item[1] for item in iter_vars]
            # map(lambda item: msgbean.vars[item[0]] = item[1], iter_vars)

            msgbean.var_num = len(msgbean.vars) - 1
            # 固定第3个变量为flygap
            msgbean.bus_gap = msgbean.vars[3]    
        except:
            sys_logger.error("var parse error")
            return False

        if self._queue.full():
            sys_logger.debug("Queue is full, dropping oldest message.")

        # if table_num == 1136:
        #    sys_logger.info(f'{msgbean.vars}')
        # if table_num == 1137:
        #    sys_logger.info(f'{msgbean.vars}')
        # if table_num == 1138:
        #     sys_logger.info(f'{msgbean.vars}')
        
        self._queue.put(msgbean)
        return True


    def parse_netbean(self, table_num, frame):

        """
        网络消息相关解码
        TODO: 后续扩展
        """
        # 如果frame长度与帧长度标识不一致，则认为帧不合格
        if len(frame) != struct.unpack("<I", frame[4:8])[0]:
            sys_logger.error(f"Frame length mismatch: expected {struct.unpack('<I', frame[4:8])}, got {len(frame)}")
            return False

        # 如果是回令0xBB， 则不解码 
        if 0xBB != struct.unpack("<B", frame[10:11])[0]:
            self.netmsg_cnt = self.netmsg_cnt + 1
            return False

        net_bean = NetMsgBean()
        net_bean.table_num = table_num

        # 流程消息功能号        
        net_bean.function_no = struct.unpack("<B", frame[8:9])[0]
        # 流程消息子功能号
        net_bean.sub_function_no = struct.unpack("<B", frame[9:10])[0]
        # 终端号编码
        net_bean.destination_id = struct.unpack("<B", frame[11:12])[0]
        # 有效编码的数量
        net_bean.code_num = struct.unpack("<B", frame[12:13])[0]

        iter_vars = struct.iter_unpack("<HddB", frame[Constants.FLOW_FRAME_HEAD_LEN: len(frame) - 6])
        try:
            for item in iter_vars:

                code = FlowCode()
                code.code = item[0]                 # 网络编码
                code.measured_value = item[1]       # 实测值
                code.relative_value = item[2]       # 偏差值
                code.flag = item[3]                 # 合格标记
                net_bean.codes.append(code)
        except:
            sys_logger.error("flow var parse error")
            return False

        if self._queue.full():
            sys_logger.debug("Net Queue is full, dropping oldest message.")

        self._queue.put(net_bean)

        return True




# test example
if __name__ == "__main__":
    # 测试可行性
    # read configs
    ip = config_singleton.udp_setting["ip"]
    port = config_singleton.udp_setting["port"]
    maxsize = config_singleton.udp_setting["queue_maxsize"]
    udp_recv = Udp_Multicast_Receiver(ip, port, maxsize)

    parser_queue_size = config_singleton.parse_configs["max_msgbean_size"]
    drop_bytes = config_singleton.parse_configs["drop_bytes_everytime"]
    parser = Parser(udp_recv=udp_recv, max_msgbean_size=parser_queue_size, drop_bytes=drop_bytes)

    thread = threading.Thread(target=parser.do_parse)
    thread.start()

    thread_udp = threading.Thread(target=udp_recv.do_receive)
    thread_udp.start()

    thread_udp.join()

    print("thread end.")

